package com.dongdong.bookstore.module.pms.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dongdong.bookstore.common.exception.ApiException;
import com.dongdong.bookstore.common.exception.Asserts;
import com.dongdong.bookstore.module.pms.dto.BookCategroyNode;
import com.dongdong.bookstore.module.pms.dto.BookDto;
import com.dongdong.bookstore.module.pms.enums.FileType;
import com.dongdong.bookstore.module.pms.mapper.BookFileRelationMapper;
import com.dongdong.bookstore.module.pms.model.Book;
import com.dongdong.bookstore.module.pms.mapper.BookMapper;
import com.dongdong.bookstore.module.pms.model.BookFileRelation;
import com.dongdong.bookstore.module.pms.service.BookCategoryService;
import com.dongdong.bookstore.module.pms.service.BookFileRelationService;
import com.dongdong.bookstore.module.pms.service.BookService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dongdong.bookstore.module.ums.model.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 * 书籍  服务实现类
 * </p>
 *
 * @author chiangkai
 * @since 2021-11-07
 */
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {

    @Autowired
    private BookFileRelationService bookFileRelationService;

    @Autowired
    private BookCategoryService bookCategoryService;

    @SuppressWarnings("AlibabaTransactionMustHaveRollback")
    @Override
    @Transactional
    public boolean create(BookDto dto) {
        Book book = new Book();
        BeanUtils.copyProperties(dto, book);
        int insert = baseMapper.insert(book);
        if (!(insert > 0)) {
            throw new ApiException("添加书籍失败");
        }
        Long bookId = book.getId();
        List<BookFileRelation> bookFileRelations = insertFileList(dto.getAudios(), dto.getFiles(), bookId);
        bookFileRelationService.saveBatch(bookFileRelations);
        return true;
    }


    private List<BookFileRelation> insertFileList(List<Long> audios, List<Long> files, Long bookId) {
        List<BookFileRelation> fileList = new ArrayList<>();
        if (!ArrayUtil.isEmpty(audios)) {
            audios.forEach(audioId -> {
                BookFileRelation bookFileRelation = new BookFileRelation();
                bookFileRelation.setBookId(bookId);
                bookFileRelation.setFileId(audioId);
                bookFileRelation.setType(FileType.common.ordinal());
                fileList.add(bookFileRelation);
            });
        }
        if (!ArrayUtil.isEmpty(files)) {
            files.forEach(audioId -> {
                BookFileRelation bookFileRelation = new BookFileRelation()
                        .setBookId(bookId).setFileId(audioId)
                        .setType(FileType.audio.ordinal());
                fileList.add(bookFileRelation);
            });
        }
        return fileList;
    }


    @Override
    public boolean delete(Long id) {
        return removeById(id);
    }

    @Override
    public boolean updateState(Long id, Integer state) {
        Book book = getById(id);
        Asserts.isNull(book, "修改状态的书籍不存在");
        book.setState(state);
        return updateById(book);
    }

    @Override
    public boolean update(Long id, BookDto dto) {
        Book book = new Book();
        Asserts.isNull(getById(id), "修改的书籍不存在");
        BeanUtils.copyProperties(dto, book);
        book.setId(id);
        QueryWrapper<BookFileRelation> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(BookFileRelation::getBookId, id);
        bookFileRelationService.remove(wrapper);
        if (dto.getAudios().size() + dto.getFiles().size() > 0) {
            List<BookFileRelation> bookFileRelations = insertFileList(dto.getAudios(), dto.getFiles(), id);
            bookFileRelationService.saveBatch(bookFileRelations);
        }
        return true;
    }

    @Override
    public Page<Book> list(String keyword, Long cateId, Long subId, String orderBy, Integer isAsc, Integer pageSize, Integer pageNum) {
        Page<Book> page = new Page<>(pageNum, pageSize);
        QueryWrapper<Book> wrapper = new QueryWrapper<>();
        if (StrUtil.isNotEmpty(keyword)) {
            wrapper.like("name", keyword).or().like("author", keyword);
        }
        if (subId != null) {
            wrapper.eq("subject_id", cateId);
        }
        if (cateId != null) {
            List<BookCategroyNode> bookCategroyNodes = bookCategoryService.listTree();
            BookCategroyNode target = null;
            getNodeById(bookCategroyNodes, cateId, target);
            if (target != null) {
                List<Long> cateIds = new ArrayList<>();
                getIds(target, cateIds);
                wrapper.in("category_id", cateIds);
            }
        }
        String targetOrderBy = "id";
        boolean Asc = false;
        if (isAsc != 0) {
            Asc = true;
        }
        if (StrUtil.isNotEmpty(orderBy)) {
            if (orderBy.equals("price")) {
                targetOrderBy = "price";
            }
            if (orderBy.equals("sort")) {
                targetOrderBy = "sort";
            }
        }
        wrapper.orderBy(true, Asc, targetOrderBy);
        return page(page, wrapper);
    }

    private void getIds(BookCategroyNode target, List<Long> cateIds) {
        cateIds.add(target.getId());
        if (CollUtil.isNotEmpty(target.getChildren())) {
            target.getChildren().forEach(node -> {
                getIds(node, cateIds);
            });
        }
    }

    /**
     * 深度优先遍历树的目标节点
     */
    private void getNodeById(List<BookCategroyNode> bookCategroyNodes, Long categoryId, BookCategroyNode target) {
        Iterator<BookCategroyNode> iterator = bookCategroyNodes.iterator();
        if (iterator.hasNext()) {
            if (target != null) {
                return;
            }
            BookCategroyNode next = iterator.next();
            if (next.getId().equals(categoryId)) {
                target = next;
                return;
            }
            if (CollUtil.isNotEmpty(next.getChildren())) {
                getNodeById(bookCategroyNodes, categoryId, target);
            }
        }
    }
}
